// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/android/network_library.h"

#include "base/android/context_utils.h"
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/logging.h"
#include "jni/AndroidNetworkLibrary_jni.h"

using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
using base::android::GetApplicationContext;
using base::android::ScopedJavaLocalRef;
using base::android::ToJavaArrayOfByteArray;
using base::android::ToJavaByteArray;

namespace net {
namespace android {

    void VerifyX509CertChain(const std::vector<std::string>& cert_chain,
        const std::string& auth_type,
        const std::string& host,
        CertVerifyStatusAndroid* status,
        bool* is_issued_by_known_root,
        std::vector<std::string>* verified_chain)
    {
        JNIEnv* env = AttachCurrentThread();

        ScopedJavaLocalRef<jobjectArray> chain_byte_array = ToJavaArrayOfByteArray(env, cert_chain);
        DCHECK(!chain_byte_array.is_null());

        ScopedJavaLocalRef<jstring> auth_string = ConvertUTF8ToJavaString(env, auth_type);
        DCHECK(!auth_string.is_null());

        ScopedJavaLocalRef<jstring> host_string = ConvertUTF8ToJavaString(env, host);
        DCHECK(!host_string.is_null());

        ScopedJavaLocalRef<jobject> result = Java_AndroidNetworkLibrary_verifyServerCertificates(
            env, chain_byte_array.obj(), auth_string.obj(), host_string.obj());

        ExtractCertVerifyResult(result.obj(),
            status, is_issued_by_known_root, verified_chain);
    }

    void AddTestRootCertificate(const uint8_t* cert, size_t len)
    {
        JNIEnv* env = AttachCurrentThread();
        ScopedJavaLocalRef<jbyteArray> cert_array = ToJavaByteArray(env, cert, len);
        DCHECK(!cert_array.is_null());
        Java_AndroidNetworkLibrary_addTestRootCertificate(env, cert_array.obj());
    }

    void ClearTestRootCertificates()
    {
        JNIEnv* env = AttachCurrentThread();
        Java_AndroidNetworkLibrary_clearTestRootCertificates(env);
    }

    bool StoreKeyPair(const uint8_t* public_key,
        size_t public_len,
        const uint8_t* private_key,
        size_t private_len)
    {
        JNIEnv* env = AttachCurrentThread();
        ScopedJavaLocalRef<jbyteArray> public_array = ToJavaByteArray(env, public_key, public_len);
        ScopedJavaLocalRef<jbyteArray> private_array = ToJavaByteArray(env, private_key, private_len);
        jboolean ret = Java_AndroidNetworkLibrary_storeKeyPair(env,
            GetApplicationContext(), public_array.obj(), private_array.obj());
        LOG_IF(WARNING, !ret) << "Call to Java_AndroidNetworkLibrary_storeKeyPair failed";
        return ret;
    }

    void StoreCertificate(net::CertificateMimeType cert_type,
        const void* data,
        size_t data_len)
    {
        JNIEnv* env = AttachCurrentThread();
        ScopedJavaLocalRef<jbyteArray> data_array = ToJavaByteArray(env, reinterpret_cast<const uint8_t*>(data), data_len);
        jboolean ret = Java_AndroidNetworkLibrary_storeCertificate(env,
            GetApplicationContext(), cert_type, data_array.obj());
        LOG_IF(WARNING, !ret) << "Call to Java_AndroidNetworkLibrary_storeCertificate"
                                 " failed";
        // Intentionally do not return 'ret', there is little the caller can
        // do in case of failure (the CertInstaller itself will deal with
        // incorrect data and display the appropriate toast).
    }

    bool HaveOnlyLoopbackAddresses()
    {
        JNIEnv* env = AttachCurrentThread();
        return Java_AndroidNetworkLibrary_haveOnlyLoopbackAddresses(env);
    }

    bool GetMimeTypeFromExtension(const std::string& extension,
        std::string* result)
    {
        JNIEnv* env = AttachCurrentThread();

        ScopedJavaLocalRef<jstring> extension_string = ConvertUTF8ToJavaString(env, extension);
        ScopedJavaLocalRef<jstring> ret = Java_AndroidNetworkLibrary_getMimeTypeFromExtension(
            env, extension_string.obj());

        if (!ret.obj())
            return false;
        *result = ConvertJavaStringToUTF8(ret);
        return true;
    }

    std::string GetTelephonyNetworkCountryIso()
    {
        return base::android::ConvertJavaStringToUTF8(
            Java_AndroidNetworkLibrary_getNetworkCountryIso(
                base::android::AttachCurrentThread(),
                base::android::GetApplicationContext()));
    }

    std::string GetTelephonyNetworkOperator()
    {
        return base::android::ConvertJavaStringToUTF8(
            Java_AndroidNetworkLibrary_getNetworkOperator(
                base::android::AttachCurrentThread(),
                base::android::GetApplicationContext()));
    }

    std::string GetTelephonySimOperator()
    {
        return base::android::ConvertJavaStringToUTF8(
            Java_AndroidNetworkLibrary_getSimOperator(
                base::android::AttachCurrentThread(),
                base::android::GetApplicationContext()));
    }

    bool GetIsRoaming()
    {
        return Java_AndroidNetworkLibrary_getIsRoaming(
            base::android::AttachCurrentThread(),
            base::android::GetApplicationContext());
    }

    bool RegisterNetworkLibrary(JNIEnv* env)
    {
        return RegisterNativesImpl(env);
    }

} // namespace android
} // namespace net
